This is the Data Visualization Project from the Udemy course Data Science and Machine Learning Bootcamp, taught by Jose Portilla.
The source of the data is the Economist.
I am not following exactly the requirements set out by the course. The reason is that, in addition to the data visualization aspects of the project, I also want to practise using hypothesis testing.
Key Points
- HDI is the Human Development Index, created by the United Nations. The HDI “is a summary measure of average achievement in key dimensions of human development: a long and healthy life, being knowledgeable and have a decent standard of living”.United Nations Development Programme, Human Development Reports. The HDI is measured on a scale of 0-1, with 0 being the lowest score (i.e. people in that country have a very low quality of life) and 1 (i.e. people have a very low quality of life).
- CPI is the Corruption Perceptions Index, developed by Transparency International. The CPI “ranks 180 countries and territories by their perceived levels of public sector corruption, according to experts and business people.”Transparency International. CPI is measured on a scale of 0-100, with 0 being very corrupt and 100 being very clean.
Hypothesis
My starting hypothesis is that HDI is positively correlated with CPI. That is: * a country with a low HDI will have a low CPI * a country with a medium HDI will have a medium CPI * a country with a high HDI will have a high CPI. H1 = correlation(HDI,CPI) > 0
This means that the null hypothesis can be stated as:
HDI is negatively correlated with CPI, or there is no correlation H0 = correlation(HDI,CPI) <= 0
So, the purposes of my project are: 1. To test whether the null hypothesis can be rejected 2. To visualize the data using ggplot2
Import the ggplot2 data.table libraries and use fread to load the csv file ‘Economist_Assignment_Data.csv’ into a dataframe called df (Hint: use drop=1 to skip the first column)
library(ggplot2)
Registered S3 method overwritten by 'dplyr':
method from
print.rowwise_df
library(ggthemes)
library(readr)
library(dplyr)
Attaching package: ‘dplyr’
The following objects are masked from ‘package:stats’:
filter, lag
The following objects are masked from ‘package:base’:
intersect, setdiff, setequal, union
df <- read.csv('./Training Exercises/Capstone and Data Viz Projects/Data Visualization Project/Economist_Assignment_Data.csv')
str(df)
'data.frame': 173 obs. of 6 variables:
$ X : int 1 2 3 4 5 6 7 8 9 10 ...
$ Country : Factor w/ 173 levels "Afghanistan",..: 1 2 3 4 5 6 7 8 9 10 ...
$ HDI.Rank: int 172 70 96 148 45 86 2 19 91 53 ...
$ HDI : num 0.398 0.739 0.698 0.486 0.797 0.716 0.929 0.885 0.7 0.771 ...
$ CPI : num 1.5 3.1 2.9 2 3 2.6 8.8 7.8 2.4 7.3 ...
$ Region : Factor w/ 6 levels "Americas","Asia Pacific",..: 2 3 5 6 1 3 2 4 3 1 ...
colnames(df)
[1] "X" "Country" "HDI.Rank" "HDI" "CPI" "Region"
nrow(df)
[1] 173
## Check the head of df
head(df)
## Use ggplot() + geom_point() to create a scatter plot object called pl. You will need to specify x=CPI and y=HDI and color=Region as aesthetics
#pl <- ggplot(df, aes(x=CPI,y=HDI)) + geom_point(aes(color=Region))
## Change the points to be larger empty circles. (You'll have to go back and add arguments to geom_point() and reassign it to pl.) You'll need to figure out what shape= and size=
pl <- ggplot(df, aes(x=CPI,y=HDI)) + geom_point(aes(color=Region), shape = 1, size=3 )
pl

Add geom_smooth(aes(group=1)) to add a trend line
pl + geom_smooth(aes(group=1))

We want to further edit this trend line. Add the following arguments to geom_smooth (outside of aes):
method = ‘lm’ formula = y ~ log(x) se = FALSE color = ‘red’ For more info on these arguments, check out the documentation under the Arguments list for details.
Assign all of this to pl2
pl2 <- pl + geom_smooth(aes(group=1), method = 'lm', formula = y ~ log(x), se=FALSE, color='red')
pl2

It’s really starting to look similar! But we still need to add labels, we can use geom_text! Add geom_text(aes(label=Country)) to pl2 and see what happens. (Hint: It should be way too many labels)
pl2 + geom_text(aes(label=Country))

Labeling a subset is actually pretty tricky! So we’re just going to give you the answer since it would require manually selecting the subset of countries we want to label!
pointsToLabel <- c("Russia", "Venezuela", "Iraq", "Myanmar", "Sudan", "Afghanistan", "Congo", "Greece", "Argentina", "Brazil", "India", "Italy", "China", "South Africa", "Spain", "Botswana", "Cape Verde", "Bhutan", "Rwanda", "France", "United States", "Germany", "Britain", "Barbados", "Norway", "Japan", "New Zealand", "Singapore")
pl3 <- pl2 + geom_text(aes(label = Country), color = "gray20", fontface='bold',
data = subset(df, Country %in% pointsToLabel),check_overlap = TRUE)
pl3

## Almost there! Still not perfect, but good enough for this assignment. Later on we’ll see why interactive plots are better for labeling. Now let’s just add some labels and a theme, set the x and y scales and we’re done!
Add theme_bw() to your plot and save this to pl4
pl4 <- pl3 + theme_bw()
pl4

Add scale_x_continuous() and set the following arguments:
name = Same x axis as the Economist Plot limits = Pass a vector of appropriate x limits breaks = 1:10
pl4 <- pl4 + scale_x_continuous(name='Corruption Perceptions Index, 2011(10=least corrupt)', limits = c(0.9,10.5), breaks = 1:10)
pl4

Now use scale_y_continuous to do similar operations to the y axis!
pl4 <- pl4 + scale_y_continuous(name='Human Development Index, 2011 (1=Best)', limits = c(0.2,1.0))
pl4

Finally use ggtitle() to add a string as a title.
pl4 <- pl4 + ggtitle('Corruption and Human Development') + theme_economist()
library(plotly)
Registered S3 method overwritten by 'data.table':
method from
print.data.table
Registered S3 methods overwritten by 'htmltools':
method from
print.html tools:rstudio
print.shiny.tag tools:rstudio
print.shiny.tag.list tools:rstudio
Registered S3 method overwritten by 'htmlwidgets':
method from
print.htmlwidget tools:rstudio
Attaching package: ‘plotly’
The following object is masked from ‘package:ggplot2’:
last_plot
The following object is masked from ‘package:stats’:
filter
The following object is masked from ‘package:graphics’:
layout
gpl4 <- ggplotly(pl4)
gpl4
Results
A look at the graph shows a fairly clear positive correlation between HDI and CPI. I would estimate that it’s somewhere between 0.5 and 1. Therefore, it looks like we can reject the null hypothesis.
Hang on! What about significance? Is it possible the positive correlation could be due to chance, and that the difference is not statistically significant?
# calculate the correlation coefficient (because I haven't specified a method, this will use the default Pearson Correlation Coefficient)
correlationCoefficient <- cor(df$HDI, df$CPI)
library(stringr)
str_glue("Correlation Coefficient: {correlationCoefficient}")
Correlation Coefficient: 0.704870476914723
Use the cor.test() function to test the hypothesis. This will find the p-value.
correlationTest <- cor.test(df$HDI, df$CPI)
# class(correlationTest)
correlationTest
Pearson's product-moment correlation
data: df$HDI and df$CPI
t = 12.994, df = 171, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
0.6209764 0.7727980
sample estimates:
cor
0.7048705
p_value <- format(2.2e-16, scientific = FALSE)
str_glue("P-value: {p_value}")
P-value: 0.00000000000000022
Conclusion: we can see that the p-value is 0.00000000000000022, which is less than 0.05 (5%), which is the significance level I am using. The p-value is the probability that we would have found the current result if the correlation coefficient was zero. That is, there would be a 5% possibility of getting these results, by chance alone. Because the p-value is less than 0.05, we can reject that possibility. Therefore, we can reject the null hypothesis.
LS0tCnRpdGxlOiAiRGF0YSBWaXN1YWxpemF0aW9uIFByb2plY3QiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KIApUaGlzIGlzIHRoZSBEYXRhIFZpc3VhbGl6YXRpb24gUHJvamVjdCBmcm9tIHRoZSBVZGVteSBjb3Vyc2UgW0RhdGEgU2NpZW5jZSBhbmQgTWFjaGluZSBMZWFybmluZyBCb290Y2FtcF0oaHR0cHM6Ly93d3cudWRlbXkuY29tL2NvdXJzZS9kYXRhLXNjaWVuY2UtYW5kLW1hY2hpbmUtbGVhcm5pbmctYm9vdGNhbXAtd2l0aC1yL2xlYXJuL2xlY3R1cmUvNTM5NzcyMiNjb250ZW50KSwgdGF1Z2h0IGJ5IEpvc2UgUG9ydGlsbGEuCgpUaGUgc291cmNlIG9mIHRoZSBkYXRhIGlzIHRoZSBbRWNvbm9taXN0XShodHRwczovL3d3dy5lY29ub21pc3QuY29tL2dyYXBoaWMtZGV0YWlsLzIwMTEvMTIvMDIvY29ycm9zaXZlLWNvcnJ1cHRpb24pLgoKSSBhbSBub3QgZm9sbG93aW5nIGV4YWN0bHkgdGhlIHJlcXVpcmVtZW50cyBzZXQgb3V0IGJ5IHRoZSBjb3Vyc2UuIFRoZSByZWFzb24gaXMgdGhhdCwgaW4gYWRkaXRpb24gdG8gdGhlIGRhdGEgdmlzdWFsaXphdGlvbiBhc3BlY3RzIG9mIHRoZSBwcm9qZWN0LCBJIGFsc28gd2FudCB0byBwcmFjdGlzZSB1c2luZyBoeXBvdGhlc2lzIHRlc3RpbmcuCgojIyBLZXkgUG9pbnRzCiogSERJIGlzIHRoZSBIdW1hbiBEZXZlbG9wbWVudCBJbmRleCwgY3JlYXRlZCBieSB0aGUgVW5pdGVkIE5hdGlvbnMuIFRoZSBIREkgImlzIGEgc3VtbWFyeSBtZWFzdXJlIG9mIGF2ZXJhZ2UgYWNoaWV2ZW1lbnQgaW4ga2V5IGRpbWVuc2lvbnMgb2YgaHVtYW4gZGV2ZWxvcG1lbnQ6IGEgbG9uZyBhbmQgaGVhbHRoeSBsaWZlLCBiZWluZyBrbm93bGVkZ2VhYmxlIGFuZCBoYXZlIGEgZGVjZW50IHN0YW5kYXJkIG9mIGxpdmluZyIuW1VuaXRlZCBOYXRpb25zIERldmVsb3BtZW50IFByb2dyYW1tZSwgSHVtYW4gRGV2ZWxvcG1lbnQgUmVwb3J0c10oaHR0cDovL2hkci51bmRwLm9yZy9lbi9jb250ZW50L2h1bWFuLWRldmVsb3BtZW50LWluZGV4LWhkaSkuIFRoZSBIREkgaXMgbWVhc3VyZWQgb24gYSBzY2FsZSBvZiAwLTEsIHdpdGggMCBiZWluZyB0aGUgbG93ZXN0IHNjb3JlIChpLmUuIHBlb3BsZSBpbiB0aGF0IGNvdW50cnkgaGF2ZSBhIHZlcnkgbG93IHF1YWxpdHkgb2YgbGlmZSkgYW5kIDEgKGkuZS4gcGVvcGxlIGhhdmUgYSB2ZXJ5IGxvdyBxdWFsaXR5IG9mIGxpZmUpLgoqIENQSSBpcyB0aGUgQ29ycnVwdGlvbiBQZXJjZXB0aW9ucyBJbmRleCwgZGV2ZWxvcGVkIGJ5IFRyYW5zcGFyZW5jeSBJbnRlcm5hdGlvbmFsLiBUaGUgQ1BJICJyYW5rcyAxODAgY291bnRyaWVzIGFuZCB0ZXJyaXRvcmllcyBieSB0aGVpciBwZXJjZWl2ZWQgbGV2ZWxzIG9mIHB1YmxpYyBzZWN0b3IgY29ycnVwdGlvbiwgYWNjb3JkaW5nIHRvIGV4cGVydHMgYW5kIGJ1c2luZXNzIHBlb3BsZS4iW1RyYW5zcGFyZW5jeSBJbnRlcm5hdGlvbmFsXShodHRwczovL3d3dy50cmFuc3BhcmVuY3kub3JnL2NwaTIwMTkpLiBDUEkgaXMgbWVhc3VyZWQgb24gYSBzY2FsZSBvZiAwLTEwMCwgd2l0aCAwIGJlaW5nIHZlcnkgY29ycnVwdCBhbmQgMTAwIGJlaW5nIHZlcnkgY2xlYW4uCgojIyBIeXBvdGhlc2lzCk15IHN0YXJ0aW5nIGh5cG90aGVzaXMgaXMgdGhhdCBIREkgaXMgcG9zaXRpdmVseSBjb3JyZWxhdGVkIHdpdGggQ1BJLiBUaGF0IGlzOgoqIGEgY291bnRyeSB3aXRoIGEgbG93IEhESSB3aWxsIGhhdmUgYSBsb3cgQ1BJCiogYSBjb3VudHJ5IHdpdGggYSBtZWRpdW0gSERJIHdpbGwgaGF2ZSBhIG1lZGl1bSBDUEkgCiogYSBjb3VudHJ5IHdpdGggYSBoaWdoIEhESSB3aWxsIGhhdmUgYSBoaWdoIENQSS4KICBfSDEgPSBjb3JyZWxhdGlvbihIREksQ1BJKSA+IDBfCgpUaGlzIG1lYW5zIHRoYXQgdGhlIG51bGwgaHlwb3RoZXNpcyBjYW4gYmUgc3RhdGVkIGFzOgoKSERJIGlzIG5lZ2F0aXZlbHkgY29ycmVsYXRlZCB3aXRoIENQSSwgb3IgdGhlcmUgaXMgbm8gY29ycmVsYXRpb24KICBfSDAgPSBjb3JyZWxhdGlvbihIREksQ1BJKSA8PSAwXwoKU28sIHRoZSBwdXJwb3NlcyBvZiBteSBwcm9qZWN0IGFyZToKMS4gVG8gdGVzdCB3aGV0aGVyIHRoZSBudWxsIGh5cG90aGVzaXMgY2FuIGJlIHJlamVjdGVkCjIuIFRvIHZpc3VhbGl6ZSB0aGUgZGF0YSB1c2luZyBgZ2dwbG90MmAgCgojIyBJbXBvcnQgdGhlIGdncGxvdDIgZGF0YS50YWJsZSBsaWJyYXJpZXMgYW5kIHVzZSBmcmVhZCB0byBsb2FkIHRoZSBjc3YgZmlsZSAnRWNvbm9taXN0X0Fzc2lnbm1lbnRfRGF0YS5jc3YnIGludG8gYSBkYXRhZnJhbWUgY2FsbGVkIGRmIChIaW50OiB1c2UgZHJvcD0xIHRvIHNraXAgdGhlIGZpcnN0IGNvbHVtbikKCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2d0aGVtZXMpCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkoZHBseXIpCmRmIDwtIHJlYWQuY3N2KCcuL1RyYWluaW5nIEV4ZXJjaXNlcy9DYXBzdG9uZSBhbmQgRGF0YSBWaXogUHJvamVjdHMvRGF0YSBWaXN1YWxpemF0aW9uIFByb2plY3QvRWNvbm9taXN0X0Fzc2lnbm1lbnRfRGF0YS5jc3YnKQpzdHIoZGYpCmNvbG5hbWVzKGRmKQogCm5yb3coZGYpCgojIyBDaGVjayB0aGUgaGVhZCBvZiBkZgpoZWFkKGRmKQpgYGAKCiAjIyBVc2UgZ2dwbG90KCkgKyBnZW9tX3BvaW50KCkgdG8gY3JlYXRlIGEgc2NhdHRlciBwbG90IG9iamVjdCBjYWxsZWQgcGwuIFlvdSB3aWxsIG5lZWQgdG8gc3BlY2lmeSB4PUNQSSBhbmQgeT1IREkgYW5kIGNvbG9yPVJlZ2lvbiBhcyBhZXN0aGV0aWNzCmBgYHtyfQojcGwgPC0gZ2dwbG90KGRmLCBhZXMoeD1DUEkseT1IREkpKSArIGdlb21fcG9pbnQoYWVzKGNvbG9yPVJlZ2lvbikpCgojIyBDaGFuZ2UgdGhlIHBvaW50cyB0byBiZSBsYXJnZXIgZW1wdHkgY2lyY2xlcy4gKFlvdSdsbCBoYXZlIHRvIGdvIGJhY2sgYW5kIGFkZCBhcmd1bWVudHMgdG8gZ2VvbV9wb2ludCgpIGFuZCByZWFzc2lnbiBpdCB0byBwbC4pIFlvdSdsbCBuZWVkIHRvIGZpZ3VyZSBvdXQgd2hhdCBzaGFwZT0gYW5kIHNpemU9CnBsIDwtIGdncGxvdChkZiwgYWVzKHg9Q1BJLHk9SERJKSkgKyBnZW9tX3BvaW50KGFlcyhjb2xvcj1SZWdpb24pLCBzaGFwZSA9IDEsIHNpemU9MyApCgoKcGwKYGBgCiAKIyMgQWRkIGdlb21fc21vb3RoKGFlcyhncm91cD0xKSkgdG8gYWRkIGEgdHJlbmQgbGluZQpgYGB7cn0KcGwgKyBnZW9tX3Ntb290aChhZXMoZ3JvdXA9MSkpCmBgYAoKIyMgV2Ugd2FudCB0byBmdXJ0aGVyIGVkaXQgdGhpcyB0cmVuZCBsaW5lLiBBZGQgdGhlIGZvbGxvd2luZyBhcmd1bWVudHMgdG8gZ2VvbV9zbW9vdGggKG91dHNpZGUgb2YgYWVzKToKCm1ldGhvZCA9ICdsbScKZm9ybXVsYSA9IHkgfiBsb2coeCkKc2UgPSBGQUxTRQpjb2xvciA9ICdyZWQnCkZvciBtb3JlIGluZm8gb24gdGhlc2UgYXJndW1lbnRzLCBjaGVjayBvdXQgdGhlIGRvY3VtZW50YXRpb24gdW5kZXIgdGhlIEFyZ3VtZW50cyBsaXN0IGZvciBkZXRhaWxzLgoKQXNzaWduIGFsbCBvZiB0aGlzIHRvIHBsMgpgYGB7cn0KcGwyIDwtIHBsICsgZ2VvbV9zbW9vdGgoYWVzKGdyb3VwPTEpLCBtZXRob2QgPSAnbG0nLCBmb3JtdWxhID0geSB+IGxvZyh4KSwgc2U9RkFMU0UsIGNvbG9yPSdyZWQnKQoKcGwyCmBgYAoKIyMgSXQncyByZWFsbHkgc3RhcnRpbmcgdG8gbG9vayBzaW1pbGFyISBCdXQgd2Ugc3RpbGwgbmVlZCB0byBhZGQgbGFiZWxzLCB3ZSBjYW4gdXNlIGdlb21fdGV4dCEgQWRkIGdlb21fdGV4dChhZXMobGFiZWw9Q291bnRyeSkpIHRvIHBsMiBhbmQgc2VlIHdoYXQgaGFwcGVucy4gKEhpbnQ6IEl0IHNob3VsZCBiZSB3YXkgdG9vIG1hbnkgbGFiZWxzKQpgYGB7cn0KcGwyICsgZ2VvbV90ZXh0KGFlcyhsYWJlbD1Db3VudHJ5KSkKCmBgYAoKIyMgTGFiZWxpbmcgYSBzdWJzZXQgaXMgYWN0dWFsbHkgcHJldHR5IHRyaWNreSEgU28gd2UncmUganVzdCBnb2luZyB0byBnaXZlIHlvdSB0aGUgYW5zd2VyIHNpbmNlIGl0IHdvdWxkIHJlcXVpcmUgbWFudWFsbHkgc2VsZWN0aW5nIHRoZSBzdWJzZXQgb2YgY291bnRyaWVzIHdlIHdhbnQgdG8gbGFiZWwhCmBgYHtyfQpwb2ludHNUb0xhYmVsIDwtIGMoIlJ1c3NpYSIsICJWZW5lenVlbGEiLCAiSXJhcSIsICJNeWFubWFyIiwgIlN1ZGFuIiwgIkFmZ2hhbmlzdGFuIiwgIkNvbmdvIiwgIkdyZWVjZSIsICJBcmdlbnRpbmEiLCAiQnJhemlsIiwgIkluZGlhIiwgIkl0YWx5IiwgIkNoaW5hIiwgIlNvdXRoIEFmcmljYSIsICJTcGFpbiIsICJCb3Rzd2FuYSIsICJDYXBlIFZlcmRlIiwgIkJodXRhbiIsICJSd2FuZGEiLCAiRnJhbmNlIiwgIlVuaXRlZCBTdGF0ZXMiLCAiR2VybWFueSIsICJCcml0YWluIiwgIkJhcmJhZG9zIiwgIk5vcndheSIsICJKYXBhbiIsICJOZXcgWmVhbGFuZCIsICJTaW5nYXBvcmUiKQoKcGwzIDwtIHBsMiArIGdlb21fdGV4dChhZXMobGFiZWwgPSBDb3VudHJ5KSwgY29sb3IgPSAiZ3JheTIwIiwgZm9udGZhY2U9J2JvbGQnLAogICAgICAgICAgICAgICAgZGF0YSA9IHN1YnNldChkZiwgQ291bnRyeSAlaW4lIHBvaW50c1RvTGFiZWwpLGNoZWNrX292ZXJsYXAgPSBUUlVFKQoKcGwzCmBgYAoKIyPCoEFsbW9zdCB0aGVyZSEgU3RpbGwgbm90IHBlcmZlY3QsIGJ1dCBnb29kIGVub3VnaCBmb3IgdGhpcyBhc3NpZ25tZW50LiBMYXRlciBvbiB3ZSdsbCBzZWUgd2h5IGludGVyYWN0aXZlIHBsb3RzIGFyZSBiZXR0ZXIgZm9yIGxhYmVsaW5nLiBOb3cgbGV0J3MganVzdCBhZGQgc29tZSBsYWJlbHMgYW5kIGEgdGhlbWUsIHNldCB0aGUgeCBhbmQgeSBzY2FsZXMgYW5kIHdlJ3JlIGRvbmUhCgpBZGQgdGhlbWVfYncoKSB0byB5b3VyIHBsb3QgYW5kIHNhdmUgdGhpcyB0byBwbDQKYGBge3J9CnBsNCA8LSBwbDMgKyB0aGVtZV9idygpCnBsNApgYGAKCiMjIEFkZCBzY2FsZV94X2NvbnRpbnVvdXMoKSBhbmQgc2V0IHRoZSBmb2xsb3dpbmcgYXJndW1lbnRzOgoKbmFtZSA9IFNhbWUgeCBheGlzIGFzIHRoZSBFY29ub21pc3QgUGxvdApsaW1pdHMgPSBQYXNzIGEgdmVjdG9yIG9mIGFwcHJvcHJpYXRlIHggbGltaXRzCmJyZWFrcyA9IDE6MTAKYGBge3J9CnBsNCA8LSBwbDQgKyBzY2FsZV94X2NvbnRpbnVvdXMobmFtZT0nQ29ycnVwdGlvbiBQZXJjZXB0aW9ucyBJbmRleCwgMjAxMSgxMD1sZWFzdCBjb3JydXB0KScsIGxpbWl0cyA9IGMoMC45LDEwLjUpLCBicmVha3MgPSAxOjEwKQpwbDQKYGBgCgojIyBOb3cgdXNlIHNjYWxlX3lfY29udGludW91cyB0byBkbyBzaW1pbGFyIG9wZXJhdGlvbnMgdG8gdGhlIHkgYXhpcyEKYGBge3J9CnBsNCA8LSBwbDQgKyBzY2FsZV95X2NvbnRpbnVvdXMobmFtZT0nSHVtYW4gRGV2ZWxvcG1lbnQgSW5kZXgsIDIwMTEgKDE9QmVzdCknLCBsaW1pdHMgPSBjKDAuMiwxLjApKQpwbDQKYGBgCgojIyBGaW5hbGx5IHVzZSBnZ3RpdGxlKCkgdG8gYWRkIGEgc3RyaW5nIGFzIGEgdGl0bGUuCmBgYHtyfQpwbDQgPC0gcGw0ICsgZ2d0aXRsZSgnQ29ycnVwdGlvbiBhbmQgSHVtYW4gRGV2ZWxvcG1lbnQnKSArIHRoZW1lX2Vjb25vbWlzdCgpCgpsaWJyYXJ5KHBsb3RseSkKZ3BsNCA8LSBnZ3Bsb3RseShwbDQpCmdwbDQKYGBgCgojIyBSZXN1bHRzCkEgbG9vayBhdCB0aGUgZ3JhcGggc2hvd3MgYSBmYWlybHkgY2xlYXIgcG9zaXRpdmUgY29ycmVsYXRpb24gYmV0d2VlbiBIREkgYW5kIENQSS4gSSB3b3VsZCBlc3RpbWF0ZSB0aGF0IGl0J3Mgc29tZXdoZXJlIGJldHdlZW4gMC41IGFuZCAxLiBUaGVyZWZvcmUsIGl0IGxvb2tzIGxpa2Ugd2UgY2FuIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzLgoKSGFuZyBvbiEgV2hhdCBhYm91dCBzaWduaWZpY2FuY2U/IElzIGl0IHBvc3NpYmxlIHRoZSBwb3NpdGl2ZSBjb3JyZWxhdGlvbiBjb3VsZCBiZSBkdWUgdG8gY2hhbmNlLCBhbmQgdGhhdCB0aGUgZGlmZmVyZW5jZSBpcyBub3Qgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudD8KCmBgYHtyfQoKIyBjYWxjdWxhdGUgdGhlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IChiZWNhdXNlIEkgaGF2ZW4ndCBzcGVjaWZpZWQgYSBtZXRob2QsIHRoaXMgd2lsbCB1c2UgdGhlIGRlZmF1bHQgUGVhcnNvbiBDb3JyZWxhdGlvbiBDb2VmZmljaWVudCkKY29ycmVsYXRpb25Db2VmZmljaWVudCA8LSBjb3IoZGYkSERJLCBkZiRDUEkpCmxpYnJhcnkoc3RyaW5ncikKc3RyX2dsdWUoIkNvcnJlbGF0aW9uIENvZWZmaWNpZW50OiB7Y29ycmVsYXRpb25Db2VmZmljaWVudH0iKQpgYGAKIyMgVXNlIHRoZSBjb3IudGVzdCgpIGZ1bmN0aW9uIHRvIHRlc3QgdGhlIGh5cG90aGVzaXMuIFRoaXMgd2lsbCBmaW5kIHRoZSBwLXZhbHVlLgpgYGB7cn0KY29ycmVsYXRpb25UZXN0IDwtIGNvci50ZXN0KGRmJEhESSwgZGYkQ1BJKQojIGNsYXNzKGNvcnJlbGF0aW9uVGVzdCkKY29ycmVsYXRpb25UZXN0CnBfdmFsdWUgPC0gZm9ybWF0KDIuMmUtMTYsIHNjaWVudGlmaWMgPSBGQUxTRSkKc3RyX2dsdWUoIlAtdmFsdWU6IHtwX3ZhbHVlfSIpCmBgYAoKQ29uY2x1c2lvbjogd2UgY2FuIHNlZSB0aGF0IHRoZSBwLXZhbHVlIGlzIDAuMDAwMDAwMDAwMDAwMDAwMjIsIHdoaWNoIGlzIGxlc3MgdGhhbiAwLjA1ICg1JSksIHdoaWNoIGlzIHRoZSBzaWduaWZpY2FuY2UgbGV2ZWwgSSBhbSB1c2luZy4gVGhlIHAtdmFsdWUgaXMgdGhlIHByb2JhYmlsaXR5IHRoYXQgd2Ugd291bGQgaGF2ZSBmb3VuZCB0aGUgY3VycmVudCByZXN1bHQgaWYgdGhlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IHdhcyB6ZXJvLiBUaGF0IGlzLCB0aGVyZSB3b3VsZCBiZSBhIDUlIHBvc3NpYmlsaXR5IG9mIGdldHRpbmcgdGhlc2UgcmVzdWx0cywgYnkgY2hhbmNlIGFsb25lLiBCZWNhdXNlIHRoZSBwLXZhbHVlIGlzIGxlc3MgdGhhbiAwLjA1LCB3ZSBjYW4gcmVqZWN0IHRoYXQgcG9zc2liaWxpdHkuIFRoZXJlZm9yZSwgd2UgY2FuIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzLiAKCgoK